using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using ExamPaperEditingSystem.Models;

namespace ExamPaperEditingSystem.Services
{
    public class VectorDatabaseService : IVectorDatabaseService
    {
        private readonly IEmbeddingService _embeddingService;
        private readonly List<KnowledgeBase> _knowledgeBases;
        private readonly string _dataPath;

        public VectorDatabaseService(IEmbeddingService embeddingService)
        {
            _embeddingService = embeddingService;
            _knowledgeBases = new List<KnowledgeBase>();
            _dataPath = Path.Combine(Environment.CurrentDirectory, "Vector Knowledge Base");
            
            if (!Directory.Exists(_dataPath))
            {
                Directory.CreateDirectory(_dataPath);
            }
        }

        public async Task<string> CreateKnowledgeBaseAsync(string name, string description)
        {
            var knowledgeBase = new KnowledgeBase
            {
                Name = name,
                Description = description
            };

            _knowledgeBases.Add(knowledgeBase);
            await SaveKnowledgeBaseAsync(knowledgeBase);
            
            return knowledgeBase.Id;
        }

        public Task<List<KnowledgeBase>> GetKnowledgeBasesAsync()
        {
            return Task.FromResult(_knowledgeBases.ToList());
        }

        public Task<KnowledgeBase?> GetKnowledgeBaseAsync(string id)
        {
            var knowledgeBase = _knowledgeBases.FirstOrDefault(kb => kb.Id == id);
            return Task.FromResult(knowledgeBase);
        }

        public async Task DeleteKnowledgeBaseAsync(string id)
        {
            var knowledgeBase = _knowledgeBases.FirstOrDefault(kb => kb.Id == id);
            if (knowledgeBase != null)
            {
                _knowledgeBases.Remove(knowledgeBase);
                
                await Task.Run(() =>
                {
                    var filePath = Path.Combine(_dataPath, $"{id}.json");
                    if (File.Exists(filePath))
                    {
                        File.Delete(filePath);
                    }
                });
            }
        }

        public async Task AddDocumentAsync(string knowledgeBaseId, VectorDocument document)
        {
            var knowledgeBase = _knowledgeBases.FirstOrDefault(kb => kb.Id == knowledgeBaseId);
            if (knowledgeBase is null)
            {
                throw new ArgumentException($"知识库 {knowledgeBaseId} 不存在");
            }

            // 如果文档没有向量，则生成向量
            if (document.Embedding == null || document.Embedding.Length == 0)
            {
                document.Embedding = await _embeddingService.GetEmbeddingAsync(document.Content);
            }

            document.KnowledgeBase = knowledgeBaseId;
            knowledgeBase.Documents.Add(document);
            knowledgeBase.UpdatedAt = DateTime.Now;
            
            await SaveKnowledgeBaseAsync(knowledgeBase);
        }

        public Task<List<VectorDocument>> GetDocumentsAsync(string knowledgeBaseId)
        {
            var knowledgeBase = _knowledgeBases.FirstOrDefault(kb => kb.Id == knowledgeBaseId);
            return Task.FromResult(knowledgeBase?.Documents ?? new List<VectorDocument>());
        }

        public async Task<List<SearchResult>> SearchAsync(string knowledgeBaseId, string query, int topK = 5)
        {
            var knowledgeBase = _knowledgeBases.FirstOrDefault(kb => kb.Id == knowledgeBaseId);
            if (knowledgeBase == null)
            {
                return new List<SearchResult>();
            }

            var queryEmbedding = await _embeddingService.GetEmbeddingAsync(query);
            var results = new List<SearchResult>();

            foreach (var document in knowledgeBase.Documents)
            {
                var similarity = CalculateCosineSimilarity(queryEmbedding, document.Embedding);
                results.Add(new SearchResult
                {
                    Document = document,
                    Similarity = similarity,
                    RelevantContent = document.Content
                });
            }

            return results.OrderByDescending(r => r.Similarity).Take(topK).ToList();
        }

        public async Task<List<SearchResult>> SearchAllAsync(string query, int topK = 5)
        {
            var queryEmbedding = await _embeddingService.GetEmbeddingAsync(query);
            var results = new List<SearchResult>();

            foreach (var knowledgeBase in _knowledgeBases)
            {
                foreach (var document in knowledgeBase.Documents)
                {
                    var similarity = CalculateCosineSimilarity(queryEmbedding, document.Embedding);
                    results.Add(new SearchResult
                    {
                        Document = document,
                        Similarity = similarity,
                        RelevantContent = document.Content
                    });
                }
            }

            return results.OrderByDescending(r => r.Similarity).Take(topK).ToList();
        }

        public async Task SaveKnowledgeBaseAsync(KnowledgeBase knowledgeBase)
        {
            var filePath = Path.Combine(_dataPath, $"{knowledgeBase.Id}.json");
            var json = JsonSerializer.Serialize(knowledgeBase, new JsonSerializerOptions
            {
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });
            
            await File.WriteAllTextAsync(filePath, json);
        }

        public async Task LoadKnowledgeBasesAsync()
        {
            _knowledgeBases.Clear();
            
            if (!Directory.Exists(_dataPath))
            {
                return;
            }

            var files = Directory.GetFiles(_dataPath, "*.json");
            foreach (var file in files)
            {
                try
                {
                    var json = await File.ReadAllTextAsync(file);
                    var knowledgeBase = JsonSerializer.Deserialize<KnowledgeBase>(json, new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                    });
                    
                    if (knowledgeBase != null)
                    {
                        _knowledgeBases.Add(knowledgeBase);
                    }
                }
                catch (Exception ex)
                {
                    // 记录错误但继续加载其他文件
                    Console.WriteLine($"加载知识库文件 {file} 失败: {ex.Message}");
                }
            }
        }

        private static float CalculateCosineSimilarity(float[] vector1, float[] vector2)
        {
            if (vector1.Length != vector2.Length)
            {
                return 0f;
            }

            float dotProduct = 0f;
            float magnitude1 = 0f;
            float magnitude2 = 0f;

            for (int i = 0; i < vector1.Length; i++)
            {
                dotProduct += vector1[i] * vector2[i];
                magnitude1 += vector1[i] * vector1[i];
                magnitude2 += vector2[i] * vector2[i];
            }

            magnitude1 = (float)Math.Sqrt(magnitude1);
            magnitude2 = (float)Math.Sqrt(magnitude2);

            if (magnitude1 == 0f || magnitude2 == 0f)
            {
                return 0f;
            }

            return dotProduct / (magnitude1 * magnitude2);
        }
    }
}